﻿using System;
using UnityConfiguration.Converters;
using System.ComponentModel;

namespace UnityConfiguration.Infrastructure
{
    /// <summary>
    /// Base class for configuration elements which describe objects.
    /// </summary>
    public class InstanceDescription : TypeResolvingObject
    {
        private string _TypeName;
        private string _Value;
        private string _TypeConverterName;

        /// <summary>
        /// Returns the string name of the type of the represented object.
        /// </summary>
        public string TypeName {
            get { return _TypeName; }
            set { _TypeName = value; }
        }

        /// <summary>
        /// Optional value used when creating the represented object.
        /// </summary>
        public string Value {
            get { return _Value; }
            set { _Value = value; }
        }

        /// <summary>
        /// Type name of the type converter used to create the represented object..
        /// If not specified, the default type converter (if any) is used.
        /// </summary>
        public string TypeConverterName {
            get { return _TypeConverterName; }
            set { _TypeConverterName = value; }
        }

        /// <summary>
        /// The type converter to use to convert the value into
        /// the represented object, or null if no typeconverter is
        /// required.
        /// </summary>
        public TypeConverter TypeConverter {
            get {
                if (string.IsNullOrEmpty(Value) && string.IsNullOrEmpty(TypeConverterName)) {
                    return null;
                }

                if (!string.IsNullOrEmpty(TypeConverterName)) {
                    Type converterType = TypeResolver.ResolveType(TypeConverterName);
                    return (TypeConverter)Activator.CreateInstance(converterType);
                }

                // missing TypeConverter so use the default
                return new DefaultTypeConverter(this.Type);
            }
        }

        /// <summary>
        /// The underlying type of the represented object.
        /// </summary>
        public Type Type {
            get { return TypeResolver.ResolveType(TypeName); }
        }

        /// <summary>
        /// Indicates whether the configuration element has information.
        /// </summary>
        /// <value>
        /// <see langword="true"/> if the configuration element has information, 
        /// otherwise <see langword="false"/>.
        /// </value>
        public bool HasData {
            get {
                return !(string.IsNullOrEmpty(this.TypeName) && string.IsNullOrEmpty(this.TypeConverterName));
            }
        }

        /// <summary>
        /// Create the object represented in this section.
        /// </summary>
        /// <returns>The represented object.</returns>
        protected T CreateInstance<T>() {
            TypeConverter converter = TypeConverter;
            if (converter == null) {
                if (!string.IsNullOrEmpty(TypeName)) {
                    return (T)Activator.CreateInstance(Type);
                }
                return default(T);
            }
            return (T)converter.ConvertFrom(Value);
        }
    }
    
}
